#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include "Sock.hpp"

static const uint16_t defaultPort = 8080;

using func_t = function<string(string&)>;

class HttpServer;
class ThreadData{
public:
    ThreadData(int sock, const string& ip, const uint16_t& port, HttpServer* tsvrp)
    :_sock(sock), _ip(ip), _port(port), _tsvrp(tsvrp){

    }

    ~ThreadData(){}

    int _sock;
    string _ip;
    uint16_t _port;
    HttpServer* _tsvrp;
};

class HttpServer{
public:
    HttpServer(func_t func, int port = defaultPort):_func(func), _port(port)
    {}

    void InitServer(){
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
    }

    void HandlerHttpRequest(int sock){
        char buffer[4096];
        string request;
        ssize_t s = recv(sock, buffer, sizeof(buffer)-1, 0);
        if(s > 0){
            buffer[s] = 0;
            request = buffer;
            string response = _func(request);
            send(sock, response.c_str(), response.size(), 0);
        }
        else
            logMessage(Info, "client quit");
    }

    static void* threadRoutine(void* args){
        pthread_detach(pthread_self());
        ThreadData* td = static_cast<ThreadData*>(args);
        td->_tsvrp->HandlerHttpRequest(td->_sock);
        close(td->_sock);
        delete td;
        return nullptr;
    }
    
    void Start(){
        for(;;){
            string clientIp;
            uint16_t clientPort;
            int sock = _listensock.Accept(&clientIp, &clientPort);
            if(sock < 0)
                continue;
            
            pthread_t tid;
            ThreadData* td = new ThreadData(sock, clientIp, clientPort, this);
            pthread_create(&tid, nullptr, threadRoutine, td);
        }
    }

    ~HttpServer(){}
private:
    int _port;
    Sock _listensock;
    func_t _func;
};